import hashlib
import threading
from subprocess import Popen, PIPE, STDOUT

import ttkbootstrap as ttk
import tkinter as tk
import os
from tkinter import filedialog as fd
import tkinter.messagebox as dialog


class Tools:
    base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    command = """keytool -genkey \
            -alias key_common_alias \
            -keypass 123456 \
            -keyalg RSA \
            -keysize 2048 \
            -validity 36500 \
            -keystore {} \
            -storepass 123456 \
            -dname 'CN = (cn), OU = (ijj), O = (ijj), L = (sz), ST = (gd), C = (cn)'"""

    def __init__(self):
        self.app_id = None
        self.app_name = None
        self.output_folder = None
        self.output_folder_path = None
        self.window = ttk.Window()
        self.window.title("keystore生成器 v1.2")
        self.window.resizable(width=False, height=False)
        self.window.geometry('450x310')
        self.build()

    def run(self):
        self.window.mainloop()

    def build(self):
        self.build_app_id()
        self.build_app_name()
        self.build_output_folder_path()
        self.build_start()

    def build_app_id(self):
        ttk.Label(self.window, text="包名:").place(x=30, y=30)
        self.app_id = ttk.Entry(self.window)
        self.app_id.place(x=100, y=28)

    def build_app_name(self):
        ttk.Label(self.window, text="app名称:").place(x=30, y=100)
        self.app_name = ttk.Entry(self.window)
        self.app_name.place(x=100, y=98)

    def build_output_folder_path(self):
        ttk.Label(self.window, text="输出路径:").place(x=30, y=170)
        self.output_folder = ttk.Entry(self.window)
        self.output_folder.place(x=100, y=168)
        ttk.Button(self.window, text="选择文件夹", command=self.select_output_folder).place(x=320, y=168)

    @staticmethod
    def exe_command(command):
        process = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True)
        log_list = []
        with process.stdout:
            for line in iter(process.stdout.readline, b''):
                log = line.decode().strip()
                log_list.append(log)
        exitcode = process.wait()
        log_str = '\n'.join(log_list)
        return log_str, exitcode

    @staticmethod
    def calculate_file_hash(file_path, hash_type='md5'):
        """
        计算文件的哈希值（MD5 或 SHA1）

        :param file_path: 文件路径
        :param hash_type: 哈希类型（'md5' 或 'sha1'）
        :return: 哈希值字符串
        """
        hash_func = hashlib.md5() if hash_type == 'md5' else hashlib.sha1()
        try:
            with open(file_path, 'rb') as file:
                # 以块读取，避免大文件占用过多内存
                for chunk in iter(lambda: file.read(8192), b""):
                    hash_func.update(chunk)
            return hash_func.hexdigest()
        except FileNotFoundError:
            return f"Error: File {file_path} not found."
        except Exception as e:
            return f"Error: {str(e)}"

    def build_start(self):
        ttk.Button(self.window, text="开始", command=self.start).place(x=200, y=240)

    def start(self):
        # 校验
        if not self.app_id.get():
            dialog.showerror(title='错误', message='包名不能为空')
            return
        if not self.app_name.get():
            dialog.showerror(title='错误', message='app名不能为空')
            return
        if not self.output_folder_path:
            dialog.showerror(title='错误', message='输出文件夹不能为空')
            return
        if not os.path.exists(self.output_folder_path):
            dialog.showerror(title='错误', message='输出文件夹不存在')
            return
        # 创建线程异步执行任务
        s = threading.Thread(target=self.async_execute_tasks)
        s.daemon = True
        s.start()

    def generator_public_key(self, filename):
        public_cer = f"{filename.replace('jks', 'cer')}"
        command = f"keytool -export -alias key_common_alias -file {public_cer} -keystore {filename} -storepass 123456"
        self.exe_command(command)
        public_pem = f"{filename.replace('jks', 'pem')}"
        command = f"openssl x509 -inform der -in {public_cer} -out {public_pem}"
        self.exe_command(command)
        command = f"keytool -list -rfc --keystore {filename} -storepass 123456 | openssl x509 -inform pem -pubkey"
        log_str, _ = self.exe_command(command)
        return log_str

    def async_execute_tasks(self):
        file_folder = os.path.join(self.output_folder_path, f"{self.app_name.get()}_{self.app_id.get()}")
        if not os.path.exists(file_folder):
            os.makedirs(file_folder)
        filename = f"{file_folder}/{self.app_name.get()}_{self.app_id.get()}.jks"
        if os.path.exists(filename):
            os.remove(filename)
        command = self.command.format(filename)
        self.exe_command(command)
        # 生成公钥
        public_key = self.generator_public_key(filename)

        keystore_info_path = os.path.join(file_folder, "签名信息.txt")
        with open(keystore_info_path, "w", encoding="utf-8") as f:
            f.write(
                f"包名：{self.app_id.get()}\napp名称：{self.app_name.get()}\nMD5：{self.calculate_file_hash(filename)}\n公钥：\n{public_key}")
        dialog.showinfo(title='成功', message='签名文件已生成')

    def select_output_folder(self):
        selected_folder = fd.askdirectory()
        self.output_folder_path = selected_folder
        self.output_folder.delete(0, tk.END)
        self.output_folder.insert(0, selected_folder)


if __name__ == '__main__':
    Tools().run()
